home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Garbo
/
Garbo.cdr
/
mac
/
source
/
piemnsrc.sit
/
Pie PopupWindow.c
< prev
next >
Wrap
Text File
|
1989-09-14
|
11KB
|
375 lines
/*
* Pie PopupWindow.c - Contains the function DrawPieMenu which is callable from
* HyperCard via an XCMD interface.
*/
#include <MacTypes.h>
#include <QuickDraw.h>
#include "HyperXCmd.h"
#include "circledata.h" /* definitions of the circles used for plotting */
#define MENU_SEPARATOR ';' /* character separating menu string items */
#define ONE_HALF_POPUP_X 140 /* 1/2 the width of the popup menu */
#define ONE_HALF_POPUP_Y 70 /* 1/2 the height of the popup menu */
#define BORDER_SIZE 4 /* minimum # of pixels to have around popup */
#define MENUBAR_HEIGHT 20 /* # of pixels in Mac's menu bar */
/* Local Function Prototypes */
int DrawPieMenu(Point, char *, int, int, int, int);
char *strcpy(char *dest, char *src);
int strlen(char *str);
/* Number of different pie wedge patterns */
#define NUM_PIE_PATTERNS 14
/* The actual patterns used for the pie wedges */
long pattern[NUM_PIE_PATTERNS][2] =
{
0x77DD77DD, 0x77DD77DD,
0x88228822, 0x88228822,
0xAA55AA55, 0xAA55AA55,
0xDBB6DBB6, 0xDBB6DBB6,
0x93499349, 0x93499349,
0xCC33CC33, 0xCC33CC33,
0xAAAAAAAA, 0xAAAAAAAA,
0xC00CC00C, 0xC00CC00C,
0xF0F0F0F0, 0xF0F0F0F0,
0xCC00CC00, 0xCC00CC00,
0x18181818, 0x18181818,
0xF00FF00F, 0xF00FF00F,
0x80048004, 0x80048004,
0xC0C00C0C, 0xC0C00C0C
};
/*
* We need to have our own black pattern because the normal pen pattern
* of black is referenced off A5 as part of the QuickDraw globals and since
* this is a code resource we've built this referencing globals off A4.
*/
long black_pattern[2] = { 0xFFFFFFFF, 0xFFFFFFFF };
/* Maximum number of pie wedges allowed */
#define MAX_MENU_ITEMS 40
/* Rectangles used to hold the coordinates of the label's rectangles */
struct {
Rect r;
} label_rects[MAX_MENU_ITEMS];
/* Region table used to hold the region handles for the pie wedges */
RgnHandle pie_rgns[MAX_MENU_ITEMS];
/* The region for the center "non-hot" region is treated separately */
RgnHandle center_rgn;
/*
* Function: DrawPieMenu(windowLoc,menuList,num_menu_items,font,font_size)
*
* Inputs: Point windowLoc - Location to center the popup about.
* char *menuList - String containing comma separated menu items.
* int num_menu_items - Number of menu items in the menuList.
* int default_item - Default to highlight, 0 if no default.
* int font - Number of font to use.
* int font_size - Size of font in pixels.
*
* Outputs: Displays a pie menu to the user for selection.
*
* Returns: The number of the selected menu item or zero if none.
*
*/
int
DrawPieMenu(windowLoc,menuList,num_menu_items,default_item,font,font_size)
Point windowLoc;
char *menuList;
int num_menu_items;
int default_item;
int font;
int font_size;
{
Rect popupRect; /* rectangle of the pie popup menu */
Point mouseLoc; /* current location of the mouse */
Point start_pt; /* start point for label placement */
Point end_pt; /* end point for label placement */
WindowRecord window_rec; /* static area for pie popup window */
WindowPtr origWindow; /* save area for original grafport */
WindowPtr pieWindow; /* pointer to pie popup window */
char label_buf[80]; /* temp scratch buffer for label generation*/
char *cp; /* temp work pointer */
short label_width; /* width of label in pixels */
int label_len; /* number of characters in a label */
int i,j,k; /* temporary index variables */
int old_rgn; /* index of previously selected region */
int in_a_region; /* TRUE iff cursor is in a pie region */
int line_start; /* index of points on inner/outer circles */
int line_end; /* used to connect a label to the wedge */
int scrn_left; /* coordinate of left side of the screen */
int scrn_right; /* coordinate of right side of the screen */
int scrn_top; /* coordinate of top of the screen */
int scrn_bottom; /* coordinate of bottom of the screen */
int rgn_i_pts; /* number of points in region of inner circle */
int extra_i_pts; /* extra inner circle points to distribute */
int next_i_pt; /* index of next inner circle point to use */
int points_this_i_rgn; /* number inner points to use for current region */
int rgn_o_pts; /* number of points in region of outer circle */
int extra_o_pts; /* extra outer circle points to distribute */
int next_o_pt; /* index of next outer circle point to use */
int points_this_o_rgn; /* number outer points to use for current region */
/* Before we do any work, validate that the mouse is still depressed */
if (! StillDown())
return (0);
/* Save the grafport of the current window */
GetPort(&origWindow);
/* Obtain the dimensions of the screen we are running on */
scrn_left = origWindow->portBits.bounds.left;
scrn_right = origWindow->portBits.bounds.right;
scrn_top = origWindow->portBits.bounds.top;
scrn_bottom = origWindow->portBits.bounds.bottom;
/* Obtain the current location of the mouse to center the popup about */
GetMouse(&mouseLoc);
mouseLoc.h += windowLoc.h;
mouseLoc.v += windowLoc.v;
/* Make sure the pie popup will fit on the screen, adjust if necessary */
if ( mouseLoc.h <= (scrn_left + ONE_HALF_POPUP_X) )
mouseLoc.h = scrn_left + ONE_HALF_POPUP_X + BORDER_SIZE;
if ( (mouseLoc.h + ONE_HALF_POPUP_X) >= scrn_right )
mouseLoc.h = scrn_right - (ONE_HALF_POPUP_X + BORDER_SIZE);
if ( mouseLoc.v <= (scrn_top + ONE_HALF_POPUP_Y + MENUBAR_HEIGHT) )
mouseLoc.v = scrn_top + ONE_HALF_POPUP_Y + MENUBAR_HEIGHT + BORDER_SIZE;
if ( (mouseLoc.v + ONE_HALF_POPUP_Y) >= scrn_bottom )
mouseLoc.v = scrn_bottom - (ONE_HALF_POPUP_Y + BORDER_SIZE);
/* Create a rectangle for the popup using the adjusted coordinates */
SetRect(&popupRect, mouseLoc.h - ONE_HALF_POPUP_X, mouseLoc.v - ONE_HALF_POPUP_Y,
mouseLoc.h + ONE_HALF_POPUP_X, mouseLoc.v + ONE_HALF_POPUP_Y);
/* Open a dialog box window to place the pie menu within, and make it current */
pieWindow = NewWindow(&window_rec,&popupRect,"\pPie Popup",true, altDBoxProc,-1L,true,0);
SetPort(pieWindow);
/* The region points headers assume a 0,0 based coordinate system */
SetOrigin(-(ONE_HALF_POPUP_X),-(ONE_HALF_POPUP_Y));
/* Create the center "non-hot" region in the pie menu. */
center_rgn = NewRgn();
PenSize(1,1);
MoveTo(c_circle_points[0].x,c_circle_points[0].y);
OpenRgn();
for (i = 1; i < NUM_C_POINTS; i++) {
LineTo(c_circle_points[i].x,c_circle_points[i].y);
}
CloseRgn(center_rgn);
PenPat(black_pattern);
FrameRgn(center_rgn);
/* Dissallow more menu items than we have regions to display */
if (num_menu_items > MAX_MENU_ITEMS)
num_menu_items = MAX_MENU_ITEMS;
/* Create as many regions as their are pie slices required */
for (i = 0; i < num_menu_items; i++)
pie_rgns[i] = NewRgn();
/* Calculate the number of points to use in defining a region */
rgn_i_pts = NUM_I_POINTS / num_menu_items;
extra_i_pts = NUM_I_POINTS % num_menu_items;
rgn_o_pts = NUM_O_POINTS / num_menu_items;
extra_o_pts = NUM_O_POINTS % num_menu_items;
/* Initialize next points and next menu selection to use */
next_i_pt = 0;
next_o_pt = 0;
cp = menuList;
/* Plot the regions */
for (i = 0; i < num_menu_items; i++) {
points_this_i_rgn = rgn_i_pts;
if (extra_i_pts) {
++points_this_i_rgn;
--extra_i_pts;
}
points_this_o_rgn = rgn_o_pts;
if (extra_o_pts) {
++points_this_o_rgn;
--extra_o_pts;
}
/* Draw a line from the center of this arc to the outer circle */
line_start = (points_this_i_rgn / 2) + next_i_pt;
line_end = (points_this_o_rgn / 2) + next_o_pt;
PenSize(2,2);
MoveTo(i_circle_points[line_start].x,i_circle_points[line_start].y);
LineTo(o_circle_points[line_end].x,o_circle_points[line_end].y);
/* Put a horizontal tab 6 pixels long on the radiating line */
if ( i < (num_menu_items / 2) )
LineTo(o_circle_points[line_end].x + 6, o_circle_points[line_end].y);
else
LineTo(o_circle_points[line_end].x - 6, o_circle_points[line_end].y);
next_o_pt += points_this_o_rgn;
/* Set the typeface and style for the text. */
TextFont(font);
TextFace(0);
TextSize(font_size);
/* Isolate the next label from the MenuList and display it. */
j = 0;
while ( (*cp != MENU_SEPARATOR) && (*cp != '\0') )
label_buf[j++] = *cp++;
label_buf[j] = '\0';
++cp;
/* Calculate the number of pixels contained in this label. */
label_len = strlen(label_buf);
label_width = TextWidth(label_buf,0,label_len);
/* Calculate where the start point of the label should be located. */
if ( i < (num_menu_items / 2) ) {
SetPt(&start_pt,
o_circle_points[line_end].x + 10,
o_circle_points[line_end].y + 4);
}
else {
SetPt(&start_pt,
o_circle_points[line_end].x - (8 + label_width),
o_circle_points[line_end].y + 4);
}
/* The end point is to the left of the start by the length of the label. */
SetPt(&end_pt, (start_pt.h + label_width), start_pt.v);
MoveTo(start_pt.h,start_pt.v);
DrawText(label_buf,0,label_len);
/* Calculate the rectangle that encloses the label */
SetRect(&label_rects[i], start_pt.h - 2, start_pt.v - font_size,
end_pt.h + 2, end_pt.v + 2);
/* Open the next region, assign points, close it, fill it, remove center. */
MoveTo(0,0);
PenSize(1,1);
OpenRgn();
for (j = points_this_i_rgn; j != 0; j--, next_i_pt++)
LineTo(i_circle_points[next_i_pt].x,i_circle_points[next_i_pt].y);
LineTo(0,0);
CloseRgn(pie_rgns[i]);
DiffRgn(pie_rgns[i],center_rgn,pie_rgns[i]);
FillRgn(pie_rgns[i],pattern[i]);
}
/*
* All of the work displaying the pie popup menu is now complete.
* Track the mouse while the button is still down and highlight /
* dehilight the appropriate selections as the user moves the mouse.
*/
old_rgn = -1; /* Indicate that we aren't in any region */
while (Button()) {
SystemTask();
in_a_region = FALSE;
GetMouse(&mouseLoc);
for (i = 0; i < num_menu_items; i++) {
if (PtInRgn(mouseLoc,pie_rgns[i]) ) {
in_a_region = TRUE;
if (old_rgn == i)
break;
else {
in_a_region = TRUE;
PenPat(black_pattern);
PaintRgn(pie_rgns[i]);
InvertRect(&label_rects[i]);
if (old_rgn != -1) {
FillRgn(pie_rgns[old_rgn],pattern[old_rgn]);
InvertRect(&label_rects[old_rgn]);
}
old_rgn = i;
}
}
}
/* Deselect the previously selected region when we exit the pie regions */
if ( (in_a_region == FALSE) && (old_rgn != -1) ) {
FillRgn(pie_rgns[old_rgn],pattern[old_rgn]);
InvertRect(&label_rects[old_rgn]);
old_rgn = -1;
}
}
/* Discard events that have occurred during user's selection */
FlushEvents(everyEvent, 0);
/* Dispose of the previously created pie regions */
for (i = 0; i < num_menu_items; i++)
DisposeRgn(pie_rgns[i]);
/* Dispose of the center 'non-hot' region */
DisposeRgn(center_rgn);
/* Switch back to the original grafport and kill the pie window */
SetPort(origWindow);
CloseWindow(pieWindow);
/* Tell the caller what menu item was selected */
return ( (old_rgn == -1) ? 0 : ++old_rgn);
}
char *
strcpy(s,t)
register char *s, *t;
{
char *dest = s;
while (*s++ = *t++);
return (dest);
}
int
strlen(s)
register char *s;
{
char *p = s;
while (*p != '\0')
p++;
return(p-s);
}